///////////////////////////////////////////////////////////////////////////////
//	FILENAME:	eTAudioComponent.h
//	SUMMARY:	Implementation for a container of audio data.
//	SUPERCLASS:	Object
//	INTERFACE:	None, but it "exports" eTAudioComponentIcon and IconH.
//	PROTOCOLS:	<ComponentData,
//				ETFDSupport,HTMDSupport,LaTeXSupport>
//	AUTHOR:		Rohit Khare
//	COPYRIGHT:	(c) 1994 California Institure of Technology, eText Project
///////////////////////////////////////////////////////////////////////////////
//	IMPLEMENTATION COMMENTS
//		This is a subclass that externalizes audio components. Manages
//	a Sound object. useSound:... has been included to allow passing
//	in Sounds that are not on disk (as with paste:s)
//		We eventually want to support WAV and AIFF types (which NX Sound
//	does not. Perhaps adopt SOX code (talk to nick christopher)?
///////////////////////////////////////////////////////////////////////////////
//	HISTORY
//	07/14/94:	Created. Aliases the NeXTSTEP Sound API.
///////////////////////////////////////////////////////////////////////////////

#import "eTAudioComponent.h"
#define	_eTAudioComponentVERSION 10

@implementation eTAudioComponent
//	id theSound;

- theSound 
{	if (!theSound) theSound = [[Sound alloc] init];
	return theSound;
}
+ newSoundNamed:(const char *)theName
{
	// This is a fake implementation. see eTImageComponent for a real one.
	id newObj;
	
	newObj = [[eTAudioComponent alloc] initInDoc:nil linked:NO];
	theSound = [Sound findSoundFor:theName];
	componentName = NXUniqueString(theName);
	return newObj;
}
- useSound:(Sound *)newSound 
	  name:(const char *) newComponentName
	  path:(const char *) newCurrentPath
{
	theSound = newSound;
	componentName = NXUniqueString(newComponentName);
	currentPath = NXUniqueString(newCurrentPath);
	shouldEdit &= !isLinked;	// should we ever muck with linked snds?
	return self;
}

- readComponentFromPath:(NXAtom)newPath
{
	[super readComponentFromPath:newPath];
	// attempt to load from currentPath
	theSound = nil;
	if (currentPath && *currentPath) {
		theSound = [[Sound alloc] initFromSoundfile:currentPath];
		shouldEdit &= !isLinked;	// should we ever muck with linked snds?
	}
	if (!theSound){
		theSound = [Sound findSoundFor:"SystemBeep"];
		shouldEdit = NO;
	}
	return self;
}
- writeComponentToPath:(NXAtom)path inFormat:(int) theFormat
{
	const char *tmp;
	char target[MAXPATHLEN];
	id	 altSound;
	
	switch(theFormat) {
		case ETFD_FMT:
		//	if it's not (a link) or (clean and the target is found),
		//		if the (source is found and it's clean), copy
		//		else write.
			sprintf(target,"%s/%s",path,componentName);
			if (!((isLinked) || ((!isDirty) && (!access(target,F_OK|R_OK))))){
				if ((!isDirty) && *currentPath && 
					(!access(currentPath, F_OK|R_OK))) {
					// copy
					char cmd[2*MAXPATHLEN];

					sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target);
					system(cmd);
					currentPath = NXUniqueString(target);
				} else {
					if (!rindex(target, '.') || 
						strcasecmp(".snd", rindex(target, '.')))
							strcat(target, ".snd");
					[theSound writeSoundfile:target];
					currentPath = NXUniqueString(target);
					componentName = NXUniqueString(rindex(target,'/')+1);
				}
				isDirty=NO;
			}
			[etDoc registerComponent:componentName];
			break;
		
		case HTMD_FMT:
		case TeXD_FMT:
		// Always is an .au. If it doesn't exist, copy an .au or create one.
			if (componentName) tmp = componentName;
			else if ([theSound name]) tmp = [theSound name];
			else tmp = [[self class] name];

			sprintf(target,"%s/%s",path,tmp);
			if (!rindex(target, '.') || strcasecmp(".au", rindex(target, '.')))
				strcat(target, ".au");
			if (access(target,F_OK|R_OK) || isDirty) {
				// if currentPath is an .au, copy.
				if (rindex(currentPath, '.') &&
					(!strcasecmp(".au", rindex(currentPath, '.'))) &&
					(!access(currentPath,F_OK|R_OK))) {
					char cmd[2*MAXPATHLEN];

					sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target);
					system(cmd);
				} else {
					altSound = [[Sound alloc] init];
					[altSound copySound:theSound];
					[altSound convertToFormat:SND_FORMAT_MULAW_8
								 samplingRate:SND_RATE_CODEC
								 channelCount:1];				 
					[altSound writeSoundfile:target];
					altSound = [altSound free];
				}
			}
			[etDoc registerComponent:rindex(target,'/')+1];
			break;
	}
	return self;
}
- writeComponentToPboard:thePboard
{
	[thePboard declareTypes:&NXSoundPboard num:1 owner:nil];
	[theSound writeToPasteboard:thePboard];
	// here we copy code from the superclass because of the order of
	// addTypes: calls and the preference-order of Pasteboard
	[thePboard 	addTypes:&NXFilenamePboardType num:1 owner:nil];
	[thePboard 	writeType:NXFilenamePboardType 
				data:currentPath length:strlen(currentPath)];
	return self;
}
- addToPboard:pboard
{
	NXStream *memstream;
	
	memstream = NXOpenMemory(NULL, 0, NX_READWRITE);
	if (memstream) {
		[theSound writeSoundToStream:memstream];
		[pboard addTypes:&NXSoundPboardType num:1 owner:nil];
		[pboard writeType:NXSoundPboardType fromStream:memstream];
		NXCloseMemory(memstream, NX_FREEBUFFER);
	}
	return self;
}
- readComponentFromPboard:thePboard
{
	[super readComponentFromPboard:thePboard];
	// ok, so now we have a quasi-valid entry in currentPath
	// If the sound can init from thePboard, go right ahead.

	theSound = [[Sound alloc] initFromPasteboard:thePboard];
	if (!theSound) {
		//ok, there's no NXSoundPboardType data. Can we get a file?
		if (currentPath && *currentPath) {
			theSound = [[Sound alloc] initFromSoundfile:currentPath];
		}
		shouldEdit &= !isLinked;	// should we ever muck with linked snds?
		if (!theSound){
			theSound = [Sound findSoundFor:"SystemBeep"];
			shouldEdit = NO;
		}
	}
	// special case: If we paste raw audio data and there's no path,
	// componentName is currently "Untitled-%d"; we need to cat ".snd"
	if (!(currentPath && *currentPath)) {
		char tmp[MAXPATHLEN];	// hey, it's only stack space... :)
		
		strcpy(tmp, componentName);
		if (!rindex(tmp, '.') || strcasecmp(".snd", rindex(tmp, '.')))
			strcat(tmp, ".snd");
		componentName = NXUniqueString(tmp);
	}

	return self;
}

- readRichText:(NXStream *)stream forView:view
{
	[super readRichText:stream forView:view];
	if (currentPath && *currentPath) {
		theSound = [[Sound alloc] initFromSoundfile:currentPath];
	}
	shouldEdit &= !isLinked;	// should we ever muck with linked snds?
	if (!theSound){
		theSound = [Sound findSoundFor:"SystemBeep"];
		shouldEdit = NO;
	}
	return self;
}
- writeRichText:(NXStream *)stream forView:view
{
	// since this method is called before any writeComponents, we attempt
	// to precompute whether an extension will be added
	
	char target[MAXPATHLEN];
	
	/*if (!etDoc)*/ etDoc = [view etDoc]; // Always reset; bugfix for shared audio, 12/23
	strcpy(target, componentName);
	if (!rindex(target, '.') || strcasecmp(".snd", rindex(target, '.'))) {
		strcat(target, ".snd");
		componentName = NXUniqueString(target);
	}
	return [super writeRichText:stream forView:view];
}
- writeHTML:(NXStream *)stream forView:view
	{return [self writeHTML:stream forView:view andClose:YES];}
- writeHTML:(NXStream *)stream forView:view andClose:(BOOL)closeIt
{
	const char *tmp;

	/*if (!etDoc)*/ etDoc = [view etDoc]; // Always reset; bugfix for shared audio, 12/23
	if (componentName) tmp = componentName;
	else if ([theSound name]) tmp = [theSound name];
	else tmp = [[self class] name];
	
	NXPrintf(stream, "<A HREF=\"%V%V\">",tmp,
	((!rindex(tmp, '.') || strcmp(".au", rindex(tmp, '.')))?".au":""));
	if (closeIt) {
		NXPrintf(stream, "%v</A>",tmp);
	}
	return self;
}

- writeLaTeX:(NXStream *)stream forView:view
{
	const char *tmp;

	/*if (!etDoc)*/ etDoc = [view etDoc]; // Always reset; bugfix for shared images, 12/23
	if (componentName) tmp = componentName;
	else if ([theSound name]) tmp = [theSound name];
	else tmp = [[self class] name];
	NXPrintf(stream, "\n\\footnote{A reference to the sound %w%w}",
	tmp,((!rindex(tmp, '.') || strcmp(".au", rindex(tmp, '.')))?".au":""));
	return self;
}
@end